﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Service
{
   public class BaseService<T> where T : class, new()
    {
        private DB db;
        public BaseService(DB db)
        {
            this.db = db;
        }
        /// <summary>
        /// 新增实体，返回受影响的行数
        /// </summary>
        /// <param name="model">增加的实体</param>
        /// <returns>返回受影响的行数</returns>
        public int Add(T model)
        {
            db.Set<T>().Add(model);
            return db.SaveChanges();
        }
        /// <summary>
        /// 新增实体，返回对应的实体对象
        /// </summary>
        /// <param name="model">增加的实体</param>
        /// <returns>返回受影响的行数</returns>
        public T AddReturnModel(T model)
        {
            db.Set<T>().Add(model);
            db.SaveChanges();
            return model; 
        }
        /// <summary>
        /// 根据id删除
        /// </summary>
        /// <param name="model">必须包含要删除id的对象</param>
        /// <returns></returns>
        public int Del(T model)
        {
            db.Set<T>().Attach(model);
            db.Set<T>().Remove(model);
            return db.SaveChanges();
        }
        /// <summary>
        /// 根据条件删除（EF原生方法）
        /// </summary>
        /// <param name="delWhere"></param>
        /// <returns>返回受影响的行数</returns>
        public int DelBy(Expression<Func<T,bool>> delWhere)
        { 
            List<T> l1 = db.Set<T>().Where(delWhere).ToList();
            l1.ForEach(a =>
            {
                db.Set<T>().Attach(a);
                db.Set<T>().Remove(a);
            });
            return db.SaveChanges();
        }
        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public int Modify(T model)
        {
            DbEntityEntry entry = db.Entry<T>(model);
            entry.State = EntityState.Modified;
            return db.SaveChanges();
        }
        /// <summary>
        /// 修改属性
        /// </summary>
        /// <param name="model"></param>
        /// <param name="propertyNames">被修改的属性名数组</param>
        /// <returns></returns>
        public int Modify(T model,params string[] propertyNames)
        {
            DbEntityEntry entry = db.Entry<T>(model);
            entry.State = EntityState.Unchanged;
            foreach(string propertyName in propertyNames)
            {
                entry.Property(propertyName).IsModified = true;
            }
            return db.SaveChanges();
        }
        /// <summary>
        /// 批量修改属性
        /// </summary>
        /// <param name="model"></param>
        /// <param name="whereLambda"></param>
        /// <param name="modifiedPropertyNames"></param>
        /// <returns></returns>
        public int ModifyBy(T model,Expression<Func<T,bool>> whereLambda,params string[] modifiedPropertyNames)
        {
            List<T> l2 = db.Set<T>().Where(whereLambda).ToList();
            Type t = typeof(T);
            List<PropertyInfo> propertyInfos = t.GetProperties(BindingFlags.Instance|BindingFlags.Public).ToList();
            Dictionary<string, PropertyInfo> dicPropertys = new Dictionary<string, PropertyInfo>();
            propertyInfos.ForEach(p =>
            {
                if(modifiedPropertyNames.Contains(p.Name))
                {
                    dicPropertys.Add(p.Name, p);
                }
            });
            foreach(string propertyName in modifiedPropertyNames)
            {
                if(dicPropertys.ContainsKey(propertyName))
                {
                    PropertyInfo proInfo = dicPropertys[propertyName];
                    object newValue = proInfo.GetValue(model,null);
                    foreach(T item in l2)
                    {
                        proInfo.SetValue(item, newValue, null);
                    }
                }
            }
            return db.SaveChanges();
        }
        /// <summary>
        /// 根据条件查询单个model
        /// </summary>
        /// <param name="wherelamdba"></param>
        /// <returns></returns>
        public T  GetModel(Expression<Func<T,bool>> wherelamdba)
        {
            return db.Set<T>().Where(wherelamdba).AsNoTracking().FirstOrDefault();
        }
        /// <summary>
        /// 根据条件查询单个model并排序
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="wherelamdba"></param>
        /// <param name="orderLamdba"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public T GetModel<TKey>(Expression<Func<T,bool>> wherelamdba, Expression<Func<T, TKey>> orderLamdba,bool isAsc=true)
        {
            if(isAsc)
            {
                return db.Set<T>().Where(wherelamdba).OrderBy(orderLamdba).AsNoTracking().FirstOrDefault();
            }
            else
            {
                return db.Set<T>().Where(wherelamdba).OrderByDescending(orderLamdba).AsNoTracking().FirstOrDefault();
            }
        }
        /// <summary>
        /// 根据条件查询
        /// </summary>
        /// <param name="wherelamdba"></param>
        /// <returns></returns>
        public List<T> GetListBy(Expression<Func<T,bool>> wherelamdba)
        {
            return db.Set<T>().Where(wherelamdba).AsNoTracking().ToList();
        }
        /// <summary>
        /// 根据条件查询并排序
        /// </summary>
        /// <param name="wherelamdba"></param>
        /// <param name="orderLamdba"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public List<T> GetListBy<TKey>(Expression<Func<T, bool>> wherelamdba, Expression<Func<T, TKey>> orderLamdba,bool isAsc=true)
        {
            if(isAsc)
            {
                return db.Set<T>().Where(wherelamdba).OrderBy(orderLamdba).AsNoTracking().ToList();
            }
            else
            {
                return db.Set<T>().Where(wherelamdba).OrderByDescending(orderLamdba).AsNoTracking().ToList();
            }
        }
        /// <summary>
        /// 根据条件查询并排序，然后取前面top个
        /// </summary>
        /// <param name="top">要取得数据的个数</param>
        /// <param name="whereLamdba">查询总数据的条件</param>
        /// <param name="orderLamdba">排序条件</param>
        /// <param name="isAsc">升序</param>
        /// <returns></returns>
        public List<T> GetListBy<TKey>(int top,Expression<Func<T,bool>> whereLamdba,Expression<Func<T, TKey>> orderLamdba,bool isAsc=true)
        {
            if(isAsc)
            {
                return db.Set<T>().Where(whereLamdba).OrderBy(orderLamdba).Take(top).AsNoTracking().ToList();
            }
            else
            {
                return db.Set<T>().Where(whereLamdba).OrderByDescending(orderLamdba).Take(top).AsNoTracking().ToList();
            }
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <param name="whereLamdba">搜索条件</param>
        /// <param name="orderLamdba">排序</param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public List<T> GetPagedList<TKey>(int pageIndex,int pageSize,Expression<Func<T,bool>> whereLamdba,Expression<Func<T,TKey>> orderLamdba,bool isAsc=true)
        {
            if(isAsc)
            {
                return db.Set<T>().Where(whereLamdba).OrderBy(orderLamdba).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsNoTracking().ToList();
            }
            else
            {
                return db.Set<T>().Where(whereLamdba).OrderByDescending(orderLamdba).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsNoTracking().ToList();
            }
        }
        /// <summary>
        /// 分页查询带输出总条数
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="Count"></param>
        /// <param name="whereLamdba"></param>
        /// <param name="orderLamdba"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public List<T> GetPagedList<TKey>(int pageIndex,int pageSize,ref int Count,Expression<Func<T,bool>> whereLamdba,Expression<Func<T,TKey>> orderLamdba,bool isAsc=true)
        {
            Count = db.Set<T>().Where(whereLamdba).Count();
            if (isAsc)
            {
                return db.Set<T>().Where(whereLamdba).OrderBy(orderLamdba).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsNoTracking().ToList();
            }
            else
            {
                return db.Set<T>().Where(whereLamdba).OrderByDescending(orderLamdba).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsNoTracking().ToList();
            }
        }
    }
}
